package com.xd.core.debt.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.xd.common.base.CustomRowHeightColWidthHandler;
import com.xd.common.base.RowHeightColWidthModel;
import com.xd.common.constant.SysConstant;
import com.xd.common.exception.XkdException;
import com.xd.common.util.AESUtil;
import com.xd.common.util.SecurityUtil;
import com.xd.common.util.XkdUtil;
import com.xd.core.api.service.ApiContractService;
import com.xd.core.business.entity.IncomingInfo;
import com.xd.core.business.entity.OutInfo;
import com.xd.core.business.entity.RepaymentSchedule;
import com.xd.core.business.entity.Surrenderinfo;
import com.xd.core.business.mapper.*;
import com.xd.core.company.entity.Company;
import com.xd.core.company.entity.ElectronicTransferInfo;
import com.xd.core.company.mapper.ElectronicTransferInfoMapper;
import com.xd.core.company.service.ICompanyService;
import com.xd.core.debt.dto.*;
import com.xd.core.debt.entity.Debt;
import com.xd.core.debt.entity.DebtTransRelate;
import com.xd.core.debt.entity.RepaymentRelate;
import com.xd.core.debt.mapper.DebtMapper;
import com.xd.core.debt.mapper.DebtTransRelateMapper;
import com.xd.core.debt.service.IDebtService;
import com.xd.core.debt.service.IDebtTransRelateService;
import com.xd.core.debt.service.IRepaymentRelateService;
import com.xd.core.debt.vo.*;
import com.xd.core.mission.entity.MissionCenterInfo;
import com.xd.core.mission.mapper.MissionCenterInfoMapper;
import com.xd.core.note.eventEntity.AssignmentOfDebtEvent;
import com.xd.core.product.mapper.ProductMapper;
import com.xd.core.system.service.ISysUserService;
import jodd.util.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 债权管理对应表 服务实现类
 * </p>
 *
 * @author ZCH
 * @since 2025-02-26
 */
@Service
public class DebtServiceImpl extends ServiceImpl<DebtMapper, Debt> implements IDebtService {

    @Autowired
    private ApiContractService apiContractService;
    @Autowired
    private DebtMapper debtMapper;
    @Autowired
    private ISysUserService iSysUserService;
    @Autowired
    private ElectronicTransferInfoMapper transferInfoMapper;
    @Autowired
    private ICompanyService iCompanyService;
    @Autowired
    private IDebtTransRelateService iDebtTransRelateService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private RepaymentScheduleMapper repaymentScheduleMapper;
    @Autowired
    private IRepaymentRelateService repaymentRelateService;
    @Autowired
    private RedissonClient redisson;
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    @Value("${image.localPathDir}")
    private String localPathDir;
    @Value("${image.exportFile}")
    private String exportFile;
    @Autowired
    private MissionCenterInfoMapper missionCenterInfoMapper;
    @Value("${aes.key}")
    private String aesKey;
    @Autowired
    private DebtTransRelateMapper debtTransRelateMapper;
    @Autowired
    private OutInfoMapper outInfoMapper;
    @Autowired
    private IncomingInfoMapper incomingInfoMapper;
    @Autowired
    private CreditMapper creditMapper;
    @Autowired
    private GuaranteeSlipMapper guaranteeSlipMapper;
    @Autowired
    private InformationMapper informationMapper;
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private SurrenderinfoMapper surrenderinfoMapper;
    private static final String DEBT_LOCK_KEY = "debt_transfer:";

    /**
     * @description: 未转让债权分页查询
     * @author: ZCH
     * @date: 2025/2/27 0027 13:47
     * @param: [debtQuery]
     * @return: com.github.pagehelper.Page<com.xd.core.debtmanagement.vo.DebtPageVo>
     **/
    @Override
    public Page<DebtPageVo> getDebtList(DebtQuery debtQuery) {
        String companyType = SecurityUtil.getLoginUser().getUser().getCompanyType();
        Integer companyId = null;
        List<Integer> userIds = null;
        if (companyType.equals(SysConstant.USER_COMPANY_TYPE_ONE) || companyType.equals(SysConstant.USER_COMPANY_TYPE_FOUR)) {
            companyId = debtQuery.getCompanyId();
        } else if (companyType.equals(SysConstant.USER_COMPANY_TYPE_TOW)) {
            companyId = SecurityUtil.getLoginCompanyId();
            userIds = iSysUserService.getUserIdsByGroup();
        } else if (companyType.equals(SysConstant.USER_COMPANY_TYPE_THREE)) {//代理
            return null;
        }
        //开始分页
        PageHelper.startPage(debtQuery.getPageNum(), debtQuery.getPageSize());
        return debtMapper.selectDebtList(debtQuery, companyId, userIds);
    }

    /**
     * @return com.xd.core.debt.vo.DebtAndPreDepositPayOrderVo
     * @description 批量获取债权用于转让
     * @author Zch
     * @date 10:08 2025/6/11 星期三
     **/
    @Override
    public DebtAndPreDepositPayOrderVo getBatchDebt(GetBatchDebtDto batchDebtDto) {
        DebtAndPreDepositPayOrderVo vo = new DebtAndPreDepositPayOrderVo();
        //查询债权信息
        List<DebtInfoForTransVo> debts = debtMapper.getBatchDebt(batchDebtDto.getIds());
        if (CollUtil.isEmpty(debts))
            throw new XkdException("未查询到待转让的债权");
        debts.forEach(debt -> {
            //页面的折扣默认原价，当用户选择其他折扣价时由前端计算（（公式:待还本金+待还利息+待还罚息+逾期利息）* 折扣）
            BigDecimal purchaseAmountOfBonds = debt.getRemainingShouldRepayPrincipal()
                    .add(debt.getRemainingShouldRepayInterest())
                    .add(debt.getDefaultInterestTodo().equals(BigDecimal.ZERO) ? BigDecimal.ZERO : debt.getDefaultInterestTodo())
                    .add(debt.getOverdueInterest().equals(BigDecimal.ZERO) ? BigDecimal.ZERO : debt.getOverdueInterest())
                    .setScale(2, BigDecimal.ROUND_HALF_UP);
            debt.setPurchaseAmountOfBonds(purchaseAmountOfBonds);
        });
        // 查询预存款信息
        List<PreDepositPaymentOrderVo> paymentOrderList = transferInfoMapper.getPreDepositPaymentOrderList(batchDebtDto.getCompanyId());
        if (CollUtil.isEmpty(paymentOrderList))
            throw new XkdException("未查询到预存款信息");
        vo.setDebtInfoForTransVoList(debts);
        vo.setPreDepositPaymentOrderVoList(paymentOrderList);
        vo.setWithholdSwitch(iCompanyService.getById(batchDebtDto.getCompanyId()).getWithholdSwitch());
        return vo;
    }

    /**
     * @description: 债权转让
     * @author: ZCH
     * @date: 2025/3/3 0003 21:26
     * @param: [ids]
     * @return: void
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void debtTrans(DebtTansDto debtTansDto) {
        XkdUtil.checkNonNullProperties(debtTansDto, "debtTransInfoDto", "paymentOrderIds", "totalAmountOfBonds");
        Integer cpyId = null;
        String type = SecurityUtil.getLoginUser().getUser().getCompanyType();
        if ("1".equals(type)) {
            cpyId = debtTansDto.getPlatformId();
        } else {
            cpyId = SecurityUtil.getLoginUser().getCompany().getId();
        }
        //比较合计购债金额和预存款订单总额大小
        BigDecimal orderTotalAmount = BigDecimal.ZERO;
        //获取资方信息
        Company company = new Company();
        //使用redisson锁
        String key = DEBT_LOCK_KEY + cpyId;
        RLock redissonLock = redisson.getLock(key);
        try {
            redissonLock.lock(60 * 2, TimeUnit.SECONDS);
            //查询所有的债权信息
            List<Integer> collect = debtTansDto.getDebtTransInfoDto().stream().map(DebtInfoForTransDto::getId).collect(Collectors.toList());
            List<Debt> debtList = debtMapper.selectBatchIds(collect);
            List<Integer> outIds = debtList.stream().map(Debt::getOutId).distinct().collect(Collectors.toList());
            List<String> payPass = outInfoMapper.getPayPass(outIds);
            if (payPass.contains("2")) {
                throw new XkdException("付款通道2的债权不允许转让，请重新转让");
            }
            //存在未释放或已经转让或转让中的债权
            List<Debt> list = debtList.stream().filter(debt -> !debt.getDebtConversionStatus().equals(1) || debt.getIsReleased().equals("0") || debt.getStatus().equals(2)).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(list))
                throw new XkdException("选择的债权存在未释放或不允许转让的债权");
            //查询所有的交易流水信息
            List<ElectronicTransferInfo> transferInfos = transferInfoMapper.selectBatchIds(debtTansDto.getPaymentOrderIds());
            for (ElectronicTransferInfo info : transferInfos) {
                //判断剩余金额是否大于0
                if (info.getRemainingAmount() <= 0)
                    throw new XkdException("预存款订单剩余金额为0");
                //计算总的预存款订单金额
                double result = info.getRemainingAmount() / 100.0;
                String formattedResult = String.format("%.2f", result);
                orderTotalAmount = orderTotalAmount.add(new BigDecimal(formattedResult));
            }
            if (debtTansDto.getTotalAmountOfBonds().compareTo(orderTotalAmount) == 1)
                throw new XkdException("预存款订单总额不足,请重新选择");
            HashMap<Integer, Debt> map = new HashMap<>();
            //根据资方id获取资方企业名称并修改债权信息
            for (Debt debt : debtList) {
                map.put(debt.getId(), debt);
                //获取资方企业id
                Integer companyId = debt.getCompanyId();
                //根据资方id获取资方企业名称
                company = iCompanyService.getById(companyId);
                //更新债权信息
                debt.setOriginalCreditor(company.getCompanyName());
                debt.setDebtConversionStatus(2);
                debt.setDebtTransDate(new Date());
                debtMapper.updateById(debt);
            }
            //修改流水信息及绑定债权和交易的中间联系表
            BigDecimal debtAmountRemaining = BigDecimal.ZERO;
            List<DebtTransRelate> debtTransRelates = new ArrayList<>();
            for (DebtInfoForTransDto debtInfoForTransDto : debtTansDto.getDebtTransInfoDto()) {
                debtAmountRemaining = debtInfoForTransDto.getPurchaseAmountOfBonds();//单位元
                for (ElectronicTransferInfo info : transferInfos) {
                    //获取该流水的剩余可用金额
                    double result = info.getRemainingAmount() / 100.00;
                    String formattedResult = String.format("%.2f", result);
                    BigDecimal orderAmount = new BigDecimal(formattedResult);
                    //判断一笔账单是否完全抵完
                    if (debtAmountRemaining.compareTo(BigDecimal.ZERO) == 1) {
                        //当单笔债权金额大于等于交易流水金额时，该笔交易流水金额全部抵完
                        if (debtAmountRemaining.compareTo(orderAmount) > -1) {
                            //抵完该交易的剩余可用金额(已消耗金额=原已消耗金额+该交易的剩余金额,剩余可用金额=0)
                            info.setDeductedAmount(info.getDeductedAmount() + info.getRemainingAmount());
                            info.setRemainingAmount(0L);
                            transferInfoMapper.updateById(info);
                            //重置该债权的剩余金额(将交易的剩余金额化成元)
                            debtAmountRemaining = debtAmountRemaining.subtract(new BigDecimal(formattedResult));
                        } else {
                            //该债权购债金额小于交易流水金额，该笔交易流水金额抵部分(已消耗的金额=原消耗的金额+该笔债券的购债金额)
                            BigDecimal scale = debtAmountRemaining.multiply(new BigDecimal("100")).setScale(0);
                            info.setDeductedAmount(info.getDeductedAmount() + Integer.valueOf(scale.toString()));
                            info.setRemainingAmount(info.getRemainingAmount() - Integer.valueOf(scale.toString()));
                            transferInfoMapper.updateById(info);
                            //重置该债权的剩余金额(将交易的剩余金额化成元)
                            debtAmountRemaining = BigDecimal.ZERO;
                        }
                        //获取债权转让时债权的剩余本金、利息、逾期利息、罚息、购债金额
                        BigDecimal principal = map.get(debtInfoForTransDto.getId()).getRemainingShouldRepayPrincipal();
                        BigDecimal interest = map.get(debtInfoForTransDto.getId()).getRemainingShouldRepayInterest();
                        BigDecimal todo = map.get(debtInfoForTransDto.getId()).getDefaultInterestTodo();
                        BigDecimal overdueInterest = map.get(debtInfoForTransDto.getId()).getOverdueInterest();
                        //构建中间表
                        DebtTransRelate debtTransRelate = DebtTransRelate.builder()
                                .debtId(debtInfoForTransDto.getId())
                                .orderNo(info.getOrderNo())
                                .remainingShouldRepayPrincipal(principal)
                                .remainingShouldRepayInterest(interest)
                                .defaultInterestTodo(todo)
                                .debtValue(principal.add(interest).add(todo).add(overdueInterest))
                                .overdueInterest(overdueInterest)
                                .purchaseAmountOfBonds(debtInfoForTransDto.getPurchaseAmountOfBonds())
                                .originalCreditor(company.getCompanyName())
                                .build();
                        debtTransRelates.add(debtTransRelate);
                        //将单笔购债金额插入债权表
                        debtMapper.updatePurchaseAmountOfBonds(debtInfoForTransDto.getId(), debtInfoForTransDto.getPurchaseAmountOfBonds());
                    } else {
                        //跳出流水的循环
                        break;
                    }
                }
            }
            //批量新增债权交易关系表
            iDebtTransRelateService.saveBatch(debtTransRelates);
            //债权转让确认单 和 债权转染通知书
            eventPublisher.publishEvent(new AssignmentOfDebtEvent(collect, cpyId));
        } finally {
            if (redissonLock.isHeldByCurrentThread())
                //释放锁
                redissonLock.unlock();
        }
    }

    /**
     * @description: 提前还款数据查询
     * @author: ZCH
     * @date: 2025/3/6 0006 9:52
     * @param: [id]
     * @return: com.xd.core.debt.vo.EarlyRepaymentVo
     **/
    @Override
    public EarlyRepaymentVo earlyRepaymentQuery(Integer id) {
        EarlyRepaymentVo earlyRepaymentVo = new EarlyRepaymentVo();
        if (StringUtil.isEmpty(id.toString())) {
            throw new XkdException("参数错误");
        }
        Debt debt = this.getById(id);
        //查询原始借款信息
        OrgBorrowInfo orgBorrowInfo = debtMapper.getOrgBorrowInfo(id);
        earlyRepaymentVo.setOrgBorrowInfo(orgBorrowInfo);
        if (debt.getStatus().equals(3)) {
            //查询账单信息(有逾期)
            BillInfoOverdue billInfoOverdue = debtMapper.getBillInfoOverdue(id);
            //计算结清偿还利息
            BigDecimal totalInterest = repaymentScheduleMapper.getTotalInterest(debt.getIncomingId(), debt.getOutId());
            //查询提前还款信息(有逾期)
            RepaymentInfoOverdue InfoOverdue = debtMapper.getRepaymentInfoOverdue(id);
            //计算提前还款违约金
            BigDecimal penalty = (InfoOverdue.getTotalPrincipal().add(totalInterest)).multiply(new BigDecimal(SysConstant.DEFAULT_RATE)).setScale(2, RoundingMode.HALF_UP);
            //赋值
            InfoOverdue.setInterest(totalInterest).setEarlyRepaymentPenalty(penalty);
            //计算剩余总还款额
            BigDecimal total = InfoOverdue.getTotalPrincipal().add(totalInterest).add(InfoOverdue.getOverdueInterest()).add(InfoOverdue.getDefaultInterestTodo()).add(InfoOverdue.getEarlyRepaymentPenalty());
            //从最开始逾期的那一期获取逾期天数
            String days = debt.getOverdueDays().toString();
            //赋值
            billInfoOverdue.setOverdueDays(days)
                    .setOverdueInterestRate(NumberUtil.formatPercent(Double.parseDouble(SysConstant.OVERDUE_INTEREST_RATE), 2))
                    .setLateChargeRate(NumberUtil.formatPercent(Double.parseDouble(SysConstant.LATE_CHARGE_RATE), 2))
                    .setRemainingTotalAmount(total);
            earlyRepaymentVo.setBillInfoOverdue(billInfoOverdue).setRepaymentInfoOverdue(InfoOverdue);
        } else if (debt.getStatus().equals(1)) {
            //查询账单信息(无逾期)
            BillInfoNoOverdue billInfo = debtMapper.getBillInfo(id);
            RepaymentInfoNoOverdue InfoNoOverdue = new RepaymentInfoNoOverdue();
            //根据放款id获取放款信息
            LambdaQueryWrapper<OutInfo> outWrapper = new LambdaQueryWrapper<>();
            outWrapper.eq(OutInfo::getOutId, debt.getOutId());
            OutInfo outInfo = outInfoMapper.selectOne(outWrapper);
            if (outInfo.getLoanMethod().equals("3")) {
                //获取年华利率
                BigDecimal rate = outInfo.getRate().divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
                //计算放款时间到当前的天数
                long days = repaymentScheduleMapper.getDays(debt.getOutId());
                //结款方式为到期还本付息计算到截止日期得利息
                BigDecimal interest = debt.getRemainingShouldRepayPrincipal()
                        .multiply(rate)
                        .divide(new BigDecimal("360"), 10, RoundingMode.HALF_UP)
                        .multiply(new BigDecimal(days))
                        .setScale(2, RoundingMode.HALF_UP);
                BigDecimal earlyRepaymentPenalty = debt.getRemainingShouldRepayPrincipal().add(interest).multiply(new BigDecimal(SysConstant.DEFAULT_RATE)).setScale(2, RoundingMode.HALF_UP);
                //将本金和利息等数据插入返回结果
                InfoNoOverdue.setAdvanceRepaymentOfPrincipal(debt.getRemainingShouldRepayPrincipal());
                InfoNoOverdue.setThisRepaymentOfInterest(interest);
                InfoNoOverdue.setEarlyRepaymentPenalty(earlyRepaymentPenalty);
            } else {
                //查询提前还款信息(无逾期且不为到期还本付息的借款方式)
                InfoNoOverdue = debtMapper.getRepaymentInfo(id);
                //获取产品类型
                String type = productMapper.getProductType(debt.getIncomingId());
                if (type.equals("4")) {
                    InfoNoOverdue.setEarlyRepaymentPenalty(InfoNoOverdue.getAdvanceRepaymentOfPrincipal().multiply(new BigDecimal(SysConstant.GUARANTEE_SLIP_RATE)).setScale(2, RoundingMode.HALF_UP));
                }
            }
            earlyRepaymentVo.setRepaymentInfoNoOverdue(InfoNoOverdue).setBillInfoNoOverdue(billInfo);
        }
        return earlyRepaymentVo;
    }

    /**
     * @description: 提前还款
     * @author: ZCH
     * @date: 2025/3/10 0010 14:35
     * @param: [dto]
     * @return: void
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public EarlyRepayVo earlyRepayment(EarlyRepaymentDto dto, String companyType, String isOut) {
        EarlyRepayVo vo = new EarlyRepayVo();
        // 获取当前时间判断是否可以执行提前还款
        Date now = new Date();
        // 将时间字符串转换为今天的日期时间
        //上午禁止时间
        Date startTimeMorning = DateUtil.parseTimeToday(SysConstant.MORNING_PROHIBITION_EARLY_REPAYMENT_START_TIME);
        Date endTimeMorning = DateUtil.parseTimeToday(SysConstant.MORNING_PROHIBITION_EARLY_REPAYMENT_END_TIME);
        //下午禁止时间
        Date startTimeAfterNoon = DateUtil.parseTimeToday(SysConstant.AFTERNOON_PROHIBITION_EARLY_REPAYMENT_START_TIME);
        Date endTimeAfterNoon = DateUtil.parseTimeToday(SysConstant.AFTERNOON_PROHIBITION_EARLY_REPAYMENT_END_TIME);
        // 使用DateUtil.isIn方法判断当前时间是否在区间内
        boolean isInRangeMorning = DateUtil.isIn(now, startTimeMorning, endTimeMorning);
        boolean isInRangeAfterNoon = DateUtil.isIn(now, startTimeAfterNoon, endTimeAfterNoon);
        if (isInRangeMorning || isInRangeAfterNoon) {
            throw new XkdException("当前时间禁止提前还款");
        }
        //获取债权信息
        Debt debt = this.getById(dto.getId());
        //判断支付通道
        String payPass = outInfoMapper.getPayPassByOutId(debt.getOutId());
        if ("1".equals(payPass)) {
            if ((!debt.getDebtConversionStatus().equals(3)))
                throw new XkdException("债权转让状态错误");
        }
        if (debt.getStatus().equals(2) || debt.getIsEarly().equals("1"))
            throw new XkdException("该账单已结清或该债权已是提前还款状态");
        //获取当前年月日
        LocalDate currentDate = LocalDate.now();
        // 获取公司类型(companyType不为空代表三方调用)
        String type = null;
        if (StringUtils.isNotBlank(companyType)) {
            type = companyType;
        } else {
            type = SecurityUtil.getLoginUser().getUser().getCompanyType();
        }
        // 判断是平台还是资管
        String flag = "1".equals(type) ? "1" : "2".equals(type) ? "0" : "";
        //提前还款所有本金
        BigDecimal principal = debt.getRemainingShouldRepayPrincipal();
        //判断该债权对应的借款方式
        LambdaQueryWrapper<OutInfo> outWrapper = new LambdaQueryWrapper<>();
        outWrapper.eq(OutInfo::getOutId, debt.getOutId());
        OutInfo outInfo = outInfoMapper.selectOne(outWrapper);
        //初始化提前还款总金额
        BigDecimal total = BigDecimal.ZERO;
        //正常情况提前还款
        if ("1".equals(dto.getStatus())) {
            //查询提前还款信息(无逾期)
            RepaymentInfoNoOverdue InfoNoOverdue = debtMapper.getRepaymentInfo(dto.getId());
            //本系统判断减免不能超过违约金
            if ("0".equals(isOut)) {
                if (dto.getReduceAmount().compareTo(InfoNoOverdue.getEarlyRepaymentPenalty()) == 1) {
                    throw new XkdException("减免金额不能超过提前还款违约金的金额");
                }
            }
            LambdaQueryWrapper<RepaymentSchedule> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(RepaymentSchedule::getIncomingId, debt.getIncomingId())
                    .eq(RepaymentSchedule::getOutId, debt.getOutId())
                    .gt(RepaymentSchedule::getRepaymentDate, currentDate)
                    .eq(RepaymentSchedule::getStatus, SysConstant.REPAYMENT_STATUS_ONE)
                    .orderByAsc(RepaymentSchedule::getRepaymentDate);
            List<RepaymentSchedule> scheduleList = repaymentScheduleMapper.selectList(wrapper);
            if (CollectionUtil.isEmpty(scheduleList)) {
                throw new XkdException("提前还款失败");
            }
            //根据提前还款日期获取最近一次的账单信息
            RepaymentSchedule schedule = scheduleList.get(0);
            BigDecimal interest = BigDecimal.ZERO;
            //判断借款方式是否为到期还本付息
            if (outInfo.getLoanMethod().equals("3")) {
                //计算放款时间到当前的天数
                long days = repaymentScheduleMapper.getDays(debt.getOutId());
                //获取年华利率
                BigDecimal rate = outInfo.getRate().divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
                //结款方式为到期还本付息计算到截止日期得利息
                interest = principal.multiply(rate)
                        .divide(new BigDecimal("360"), 10, RoundingMode.HALF_UP)
                        .multiply(new BigDecimal(days))
                        .setScale(2, RoundingMode.HALF_UP);
            } else {
                //获取当次提前还款的利息
                interest = schedule.getInterest();
            }
            //计算提前还款违约金（原产品）
            BigDecimal penalty = BigDecimal.ZERO;
            if (dto.getType().equals("4")) {
                penalty = principal.multiply(new BigDecimal(SysConstant.GUARANTEE_SLIP_RATE)).setScale(2, RoundingMode.HALF_UP);
            } else {
                penalty = (principal.add(interest)).multiply(new BigDecimal(SysConstant.DEFAULT_RATE)).setScale(2, RoundingMode.HALF_UP);
            }
            //计算减免后的总额
            total = principal.add(interest).add(penalty).subtract(dto.getReduceAmount());
            //三方系统判断总金额必须大于0
            if ("1".equals(isOut) && total.compareTo(BigDecimal.ZERO) == -1) {
                throw new XkdException("提前还款总金额不能小于0");
            }
            //将原来的还款计划做逻辑删除即将状态修改为提前还款
            for (RepaymentSchedule repaymentSchedule : scheduleList) {
                repaymentSchedule.setStatus(SysConstant.REPAYMENT_STATUS_FOUR);
                repaymentScheduleMapper.updateById(repaymentSchedule);
            }
            //构建还款计划记录关系表
            RepaymentRelate relate = RepaymentRelate.builder()
                    .debtId(dto.getId())
                    .principal(principal)
                    .interest(interest)
                    .penalty(penalty)
                    .reliefAmount(dto.getReduceAmount())
                    .afterReliefAmount(total)
                    .isNormal("1")
                    .build();
            repaymentRelateService.save(relate);
            //将利息等信息更新到债权表中
            debt.setCurrentRepaymentPenalty(penalty)
                    .setIsEarly("1")
                    .setEarlyType(flag)
                    .setEarlyAmount(total)
                    .setEarlyDate(schedule.getRepaymentDate());
            this.updateById(debt);

            //构建返回参数
            vo.setDebtId(debt.getId())
                    .setEarlyAmount(total)
                    .setPrincipal(principal)
                    .setInterest(interest)
                    .setPenalty(penalty)
                    .setReliefAmount(dto.getReduceAmount())
                    .setIsNormal("1")
                    .setEarlyDate(schedule.getRepaymentDate())
                    .setDisbursementDate(debt.getDisbursementDate());
        } else if (dto.getStatus().equals("3")) {
            //初始化结清偿还利息
            BigDecimal totalInterest = BigDecimal.ZERO;
            if (outInfo.getLoanMethod().equals("3")) {
                //到期还本付息的结清偿还利息就是当期的利息
                totalInterest = repaymentScheduleMapper.getInterest(debt.getIncomingId(), debt.getOutId());
            } else {
                //按月借款的结清偿还利息
                totalInterest = repaymentScheduleMapper.getTotalInterest(debt.getIncomingId(), debt.getOutId());
            }
            //计算提前还款违约金
            BigDecimal penalty = principal.add(totalInterest).multiply(new BigDecimal(SysConstant.DEFAULT_RATE)).setScale(2, RoundingMode.HALF_UP);
            BigDecimal totalAmount = principal.add(totalInterest).add(penalty).add(debt.getOverdueInterest()).add(debt.getDefaultInterestTodo()).subtract(dto.getReduceAmount());
            if(totalAmount.compareTo(BigDecimal.ZERO) == -1){
                throw new XkdException("提前结清总金额不能小于0");
            }
            Date date = new Date();
            //更新这些数据到债权信息表中
            debt.setCurrentRepaymentPenalty(penalty)
                    .setIsEarly("1")
                    .setEarlyType(flag)
                    .setEarlyAmount(totalAmount)
                    .setEarlyDate(date);
            this.updateById(debt);
            //获取最早的逾期的账单时间
            String firstOverdueDate = repaymentScheduleMapper.getFirstOverdueDate(debt.getIncomingId(), debt.getOutId());
            //构建还款计划记录关系表
            RepaymentRelate relate = RepaymentRelate.builder()
                    .debtId(dto.getId())
                    .principal(principal)
                    .interest(totalInterest)
                    .penalty(penalty)
                    .lateInterest(debt.getOverdueInterest())
                    .penaltyInterest(debt.getDefaultInterestTodo())
                    .isNormal("2")
                    .firstOverdueDate(firstOverdueDate)
                    .reliefAmount(dto.getReduceAmount())
                    .afterReliefAmount(principal.add(totalInterest).add(penalty).add(debt.getOverdueInterest()).add(debt.getDefaultInterestTodo()).subtract(dto.getReduceAmount()))
                    .build();
            repaymentRelateService.save(relate);
            //将还款计划中剩余的逾期和未还款账单标记为提前结清
            LambdaQueryWrapper<RepaymentSchedule> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(RepaymentSchedule::getStatus, Arrays.asList("0", "2"));
            wrapper.eq(RepaymentSchedule::getIncomingId, debt.getIncomingId());
            wrapper.eq(RepaymentSchedule::getOutId, debt.getOutId());
            List<RepaymentSchedule> repaymentSchedules = repaymentScheduleMapper.selectList(wrapper);
            for (RepaymentSchedule repaymentSchedule : repaymentSchedules) {
                repaymentSchedule.setStatus(SysConstant.REPAYMENT_STATUS_FIVE);
                repaymentScheduleMapper.updateById(repaymentSchedule);
            }
            //构建返回参数
            vo.setDebtId(debt.getId())
                    .setEarlyAmount(totalAmount)
                    .setPrincipal(principal)
                    .setInterest(totalInterest)
                    .setPenalty(penalty)
                    .setLateInterest(debt.getOverdueInterest())
                    .setReliefAmount(dto.getReduceAmount())
                    .setIsNormal("2")
                    .setEarlyDate(date)
                    .setDisbursementDate(debt.getDisbursementDate());
        }
        return vo;
    }

    /**
     * @description: 提前释放债权或申请公证执行书
     * @author: ZCH
     * @date: 2025/3/25 0025 13:39
     * @param: [dto]
     * @return: void
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void applyCertificate(ApplyCertificateDto dto) {
        if (ObjectUtil.isEmpty(dto.getId()) || ObjectUtil.isEmpty(dto.getFlag()))
            throw new XkdException("参数错误");
        //根据债权id获取债权信息
        Debt debt = this.getById(dto.getId());
        if (StrUtil.isNotEmpty(dto.getCertificationStatus()) && dto.getFlag().equals("1")) {
            if (!debt.getStatus().equals(SysConstant.ORDER_STATUS_THREE))
                throw new XkdException("该债权暂无法申请公证书");
            if (debt.getCertificationApplyStatus().equals("2"))
                throw new XkdException("该债权已完成申请公证执行书,请勿重复提交");
            //申请公证书
            debt.setCertificationApplyStatus(dto.getCertificationStatus());
            debt.setCertificationApplyDate(new Date());
            //点击申请完成时扣除手续费
            if (dto.getCertificationStatus().equals("2")) {
                iCompanyService.deductingBalanceMain(null, null, dto.getIncomingId(), dto.getId(), SysConstant.BUSINESS_FEE_TWO, null, null, null);
            }
        } else if (StrUtil.isNotEmpty(dto.getReleasedReason()) && dto.getFlag().equals("2")) {
            if (debt.getIsReleased().equals(SysConstant.RELEASED_STATUS_ONE))
                throw new XkdException("该债权已释放,请勿重复提交");
            //提前释放债权
            debt.setReleasedReason(dto.getReleasedReason());
            debt.setIsReleased(SysConstant.RELEASED_STATUS_ONE);
            debt.setEarlyReleasedDate(new Date());
        } else
            throw new XkdException("参数非法");
        this.updateById(debt);
    }

    /**
     * @description: 债权列表数据导出
     * @author: ZCH
     * @date: 2025/3/24 0024 9:54
     * @param: [debtQuery, id]
     * @return: void
     **/
    @Override
    public void exportDebtInfoList(DebtQuery debtQuery, Integer id) {
        String name = "债权excel文件" + UUID.randomUUID().toString().replace("-", "");
        Integer companyId = SecurityUtil.getLoginCompanyId();
        FileOutputStream fileOutputStream = null;
        MissionCenterInfo missionCenterInfo = new MissionCenterInfo();
        missionCenterInfo.setId(id);
        missionCenterInfo.setFileName(name + ".xlsx");

        String filePath = localPathDir + exportFile + "/" + companyId;
        File dirFile = new File(filePath);
        if (!dirFile.exists()) {
            dirFile.mkdirs();
        }

        try {
            List<RowHeightColWidthModel> rowHeightColWidthList = new ArrayList<>();
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 0, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 1, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 2, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 3, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 4, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 5, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 6, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 7, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 8, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 9, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 10, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 11, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 12, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 13, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 14, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 15, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 16, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 17, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 18, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 19, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 20, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 21, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 22, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 23, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 24, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 25, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 26, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 27, 20));
            File file = new File(filePath + "/" + name + ".xlsx");
            fileOutputStream = new FileOutputStream(file);

            ExcelWriter write = EasyExcel.write(fileOutputStream, DebtPageVo.class).build();
            WriteSheet writeSheet = EasyExcel.writerSheet(name).registerWriteHandler(new CustomRowHeightColWidthHandler(rowHeightColWidthList)).build();
            debtQuery.setPageSize(0);
            List<DebtPageVo> list = getDebtList(debtQuery);
            for (DebtPageVo debtPageVo : list) {
                String decryptPhone = AESUtil.decrypt(debtPageVo.getPhone(), aesKey);
                debtPageVo.setPhone(decryptPhone);
            }
            write.write(list, writeSheet);
            write.finish();
            fileOutputStream.flush();
            //修改文件状态 导出成功
            missionCenterInfo.setFileStatus(SysConstant.YSZT_FILE_STATUS_TOW);
            missionCenterInfo.setFileUrl(exportFile + "/" + companyId + "/" + name + ".xlsx");
            missionCenterInfoMapper.updateById(missionCenterInfo);
        } catch (Exception e) {
            //修改文件状态 导出失败
            missionCenterInfo.setFileStatus(SysConstant.YSZT_FILE_STATUS_THREE);
            missionCenterInfoMapper.updateById(missionCenterInfo);
            e.printStackTrace();
        } finally {
            try {
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @description: 查看单条债权详情
     * @author: ZCH
     * @date: 2025/3/25 0025 14:15
     * @param: [id]
     * @return: com.xd.core.debt.vo.DebtDetailVo
     **/
    @Override
    public DebtDetailVo getDebtOne(DebtOneDto dto) {
        XkdUtil.checkNonNullProperties(dto, "incomingId", "outId");
        //根据进件id获取产品类型
        String type = incomingInfoMapper.getType(dto.getIncomingId());
        DebtDetailVo result = debtMapper.getDebtOne(dto);
        if (ObjectUtil.isNotEmpty(result)) {
            //将产品类型插入返回对象
            result.setType(type);
            LambdaQueryWrapper<DebtTransRelate> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(DebtTransRelate::getDebtId, result.getDebtId());
            List<DebtTransRelate> list = debtTransRelateMapper.selectList(wrapper);
            if (CollUtil.isNotEmpty(list)) {
                result.setOrderNo(list.stream().map(DebtTransRelate::getOrderNo).collect(Collectors.toList()));
                result.setDebtTransRelateVo(DebtTransRelateVo.builder()
                        .remainingShouldRepayPrincipal(list.get(0).getRemainingShouldRepayPrincipal())
                        .remainingShouldRepayInterest(list.get(0).getRemainingShouldRepayInterest())
                        .overdueInterest(list.get(0).getOverdueInterest())
                        .defaultInterestTodo(list.get(0).getDefaultInterestTodo())
                        .debtValue(list.get(0).getDebtValue())
                        .purchaseAmountOfBonds(list.get(0).getPurchaseAmountOfBonds())
                        .originalCreditor(list.get(0).getOriginalCreditor())
                        .build());
            }
        }
        return result;
    }

    /***
     * @description 退保申请数据回显
     * @author Zch
     * @date 14:53 2025/6/30 星期一
     * @return com.xd.core.debt.vo.RefundApplicationVo
     **/
    @Override
    public RefundApplicationVo getRefundApplication(Integer incomingId) {
        if (StrUtil.isEmpty(incomingId.toString()))
            throw new XkdException("参数错误");
        //获取借款订单编号和保单数量
        IncomingInfo incomingInfo = incomingInfoMapper.selectById(incomingId);
        String num = guaranteeSlipMapper.getTotalNumber(incomingId);
        //获取车辆保单信息
        List<GuaranteeSlipVo> list = guaranteeSlipMapper.getGuaranteeVo(incomingId);
        //获取保单信息
        GuaranteeSlipInfo guaranteeInfo = creditMapper.getGuaranteeSlipInfo(incomingId);
        //获取提前退保账单信息
        AdvanceSurrenderInfo advanceSurrenderInfo = debtMapper.getAdvanceSurrenderInfo(incomingId);
        RefundApplicationVo vo = RefundApplicationVo.builder()
                .incomingOrder(incomingInfo.getIncomingOrder())
                .totalGuaranteeSlipNum(num)
                .guaranteeSlipVoList(list)
                .guaranteeSlipInfo(guaranteeInfo)
                .advanceSurrenderInfo(advanceSurrenderInfo)
                .build();
        return vo;
    }

    public PrincipalAndInterest updateRepaymentSchedule(Integer incomingId, BigDecimal rate, String surrenderSituation) {
        PrincipalAndInterest principalAndInterest = new PrincipalAndInterest();
        List<RepaymentSchedule> newRepaymentSchedules = new ArrayList<>();
        //获取原账单
        List<RepaymentSchedule> repaymentSchedules = repaymentScheduleMapper.selectList(new LambdaQueryWrapper<RepaymentSchedule>().eq(RepaymentSchedule::getIncomingId, incomingId));
        if (CollectionUtil.isEmpty(repaymentSchedules))
            throw new XkdException("该保单不存在还款计划");
        String historyBills = JSON.toJSONString(repaymentSchedules, SerializerFeature.WriteDateUseDateFormat,SerializerFeature.WriteMapNullValue);
        //本金总和
        BigDecimal totalPrincipal = BigDecimal.ZERO;
        //利息总和
        BigDecimal totalInterest = BigDecimal.ZERO;
        //剩余还款期数
        Integer remainingRepaymentPeriods = 0;
        //部分退保
        if ("0".equals(surrenderSituation)) {
            //生成新账单
            for (RepaymentSchedule repaymentSchedule : repaymentSchedules) {
                //判断是否是已还款，是已还款则删除并跳出
                if ("1".equals(repaymentSchedule.getStatus())) {
                    //删除已还款的记录
                    repaymentScheduleMapper.deleteById(repaymentSchedule);
                    continue;
                }
                RepaymentSchedule newSchedule = new RepaymentSchedule();
                BeanUtil.copyProperties(repaymentSchedule, newSchedule);
                //计算新的本金和利息
                BigDecimal principal = repaymentSchedule.getPrincipal();
                BigDecimal interest = repaymentSchedule.getInterest();
                principal = rate.multiply(principal).setScale(2, RoundingMode.HALF_UP);
                totalPrincipal = totalPrincipal.add(principal);
                interest = rate.multiply(interest).setScale(2, RoundingMode.HALF_UP);
                totalInterest = totalInterest.add(interest);
                newSchedule.setPrincipal(principal);
                newSchedule.setPrincipalTodo(principal);
                newSchedule.setInterest(interest);
                newSchedule.setInterestTodo(interest);
                newSchedule.setCreateTime(new Date());
                newSchedule.setAmount(principal.add(interest).setScale(2, RoundingMode.HALF_UP));
                newRepaymentSchedules.add(newSchedule);
                //删除原计划
                repaymentScheduleMapper.deleteById(repaymentSchedule);
            }
            RepaymentSchedule repaymentSchedule = newRepaymentSchedules.get(0);
            remainingRepaymentPeriods=newRepaymentSchedules.size();
            //如果不是第一期，更新后续账单变为第一期
            if (1 != repaymentSchedule.getInstallmentNumber()) {
                // 从1开始顺序设置期数
                for (int i = 0; i < newRepaymentSchedules.size(); i++) {
                    RepaymentSchedule schedule = newRepaymentSchedules.get(i);
                    schedule.setInstallmentNumber(i + 1); // 期数从1开始递增
                }
            }
            repaymentScheduleMapper.insertSchedule(newRepaymentSchedules);
        } else {
            //将还款计划的id提取出来组成集合
            List<Integer> repaymentIds = repaymentSchedules.stream().map(RepaymentSchedule::getId).collect(Collectors.toList());
            repaymentScheduleMapper.deleteBatchIds(repaymentIds);
            //将该笔订单的状态修改为已结清
            debtMapper.updateByIncomingId(incomingId);
        }
        principalAndInterest.setOrderAmount(totalPrincipal).setOrderInterest(totalInterest).setHistoryBills(historyBills);
        debtMapper.updateAmountAfterSurrender(incomingId,totalPrincipal,totalInterest,remainingRepaymentPeriods);
        return principalAndInterest;
    }

    /***
     * @description 退保申请
     * @author Zch
     * @date 10:36 2025/7/3 星期四
     * @return void
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void applySurrender(ApplySurrenderDto dto) {
        XkdUtil.checkNonNullProperties(dto, "debtId");
        if(CollUtil.isEmpty(dto.getGuaranteeSlipVoList()))
            throw new XkdException("未选择退保保单");
        //处理车牌号和保单号格式
        String carNos = dto.getGuaranteeSlipVoList().stream()
                .map(GuaranteeSlipVo::getCarNo)
                .filter(carNo -> carNo != null && !carNo.trim().isEmpty())
                .collect(Collectors.joining(","));
        String policyNos = dto.getGuaranteeSlipVoList().stream()
                .map(GuaranteeSlipVo::getPolicyNo)
                .filter(getPolicyNo -> getPolicyNo != null && !getPolicyNo.trim().isEmpty())
                .collect(Collectors.joining(","));
        if(StrUtil.isEmpty(carNos) || StrUtil.isEmpty(policyNos))
            throw new XkdException("车牌号或保单号不能为空");
        //根据债权获取退保类型
        Debt debt = this.getById(dto.getDebtId());
        if (ObjectUtil.isEmpty(debt))
            throw new XkdException("债权信息未知");
        //计划相关
        PrincipalAndInterest principalAndInterest = updateRepaymentSchedule(debt.getIncomingId(), dto.getRate(), dto.getSurrenderSituation());
        //保存退保信息
        Surrenderinfo surrenderinfo = Surrenderinfo.builder()
                .debtId(dto.getDebtId())
                .carNo(carNos)
                .policyNo(policyNos)
                .applySurrenderDate(new Date())
                .surrenderType(debt.getStatus() == 3 ? "1" : "0")
                .surrenderSituation(dto.getSurrenderSituation())
                .status("0")
                .surrenderRemainPrincipal(dto.getSurrenderRemainPrincipal())
                .surrenderCurrentInterest(dto.getSurrenderCurrentInterest())
                .totalAmount(dto.getTotalAmount())
                .shouldRefundFee(dto.getShouldRefundFee())
                .shouldLateSubmitFee(dto.getShouldLateSubmitFee())
                .otherFee(dto.getOtherFee())
                .surrenderGuaranteeTotalAmount(dto.getSurrenderGuaranteeTotalAmount())
                .reliefAmount(dto.getReliefAmount())
                .orderAmount(principalAndInterest.getOrderAmount())
                .orderInterest(principalAndInterest.getOrderInterest())
                .overdueDays(dto.getOverdueDays())
                .overdueInterest(dto.getOverdueInterest())
                .penalty(dto.getCurrentRepaymentPenalty())
                .uid(IdWorker.getId())
                .historyBills(principalAndInterest.getHistoryBills())
                .build();
        surrenderinfoMapper.insert(surrenderinfo);
        //将所选保单状态变为退保中
        guaranteeSlipMapper.applySurrender(dto.getGuaranteeSlipVoList());
    }

    /***
     * @description 分期债权
     * @author Zch
     * @date 9:40 2025/8/22 星期五
     * @return com.github.pagehelper.Page<com.xd.core.debt.vo.InstallmentDebtPageVo>
     **/
    @Override
    public Page<InstallmentDebtPageVo> getInstallmentDebtList(InstallmentDebtQuery query) {
        String companyType = SecurityUtil.getLoginUser().getUser().getCompanyType();
        Integer companyId = null;
        List<Integer> userIds = null;
        if (companyType.equals(SysConstant.USER_COMPANY_TYPE_ONE) || companyType.equals(SysConstant.USER_COMPANY_TYPE_FOUR)) {
            companyId = query.getCompanyId();
        } else if (companyType.equals(SysConstant.USER_COMPANY_TYPE_TOW)) {
            companyId = SecurityUtil.getLoginCompanyId();
            userIds = iSysUserService.getUserIdsByGroup();
        } else if (companyType.equals(SysConstant.USER_COMPANY_TYPE_THREE)) {//代理
            return null;
        }
        //开始分页
        PageHelper.startPage(query.getPageNum(), query.getPageSize());
        return debtMapper.getInstallmentDebtList(query, companyId);
    }

    /***
     * @description 修改代扣开关状态
     * @author Zch
     * @date 11:29 2025/8/25 星期一
     * @return void
     **/
    @Override
    public void changeIsWithhold(ChangeIsWithholdDto dto) {
        XkdUtil.checkNonNullProperties(dto, "debtId", "isWithhold");
        Debt debt = this.getById(dto.getDebtId());
        if (ObjectUtil.isEmpty(debt))
            throw new XkdException("债权信息错误");
        //原来的代收状态
        String withhold = debt.getIsWithhold();
        if ("0".equals(withhold) && "1".equals(dto.getIsWithhold())) {
            debt.setIsWithhold(dto.getIsWithhold());
            this.updateById(debt);
        } else {
            throw new XkdException("暂不支持不代扣变代扣");
        }
    }

    /***
     * @description 分期资产导出
     * @author Zch
     * @date 16:49 2025/9/11 星期四
     * @return void
     **/
    @Override
    public void exportGuaranteeSlipList(InstallmentDebtQuery query, Integer id) {
        String name = "分期资产excel文件" + UUID.randomUUID().toString().replace("-", "");
        Integer companyId = SecurityUtil.getLoginCompanyId();
        FileOutputStream fileOutputStream = null;
        MissionCenterInfo missionCenterInfo = new MissionCenterInfo();
        missionCenterInfo.setId(id);
        missionCenterInfo.setFileName(name + ".xlsx");

        String filePath = localPathDir + exportFile + "/" + companyId;
        File dirFile = new File(filePath);
        if (!dirFile.exists()) {
            dirFile.mkdirs();
        }

        try {
            List<RowHeightColWidthModel> rowHeightColWidthList = new ArrayList<>();
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 0, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 1, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 2, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 3, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 4, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 5, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 6, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 7, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 8, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 9, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 10, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 11, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 12, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 13, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 14, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 15, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 16, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 17, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 18, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 19, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 20, 20));
            rowHeightColWidthList.add(RowHeightColWidthModel.createColWidthModel(name, 21, 20));
            File file = new File(filePath + "/" + name + ".xlsx");
            fileOutputStream = new FileOutputStream(file);

            ExcelWriter write = EasyExcel.write(fileOutputStream, InstallmentDebtPageVo.class).build();
            WriteSheet writeSheet = EasyExcel.writerSheet(name).registerWriteHandler(new CustomRowHeightColWidthHandler(rowHeightColWidthList)).build();
            query.setPageSize(0);
            List<InstallmentDebtPageVo> list = getInstallmentDebtList(query);
            for (InstallmentDebtPageVo installmentDebtPageVo : list) {
                String decryptPhone = AESUtil.decrypt(installmentDebtPageVo.getPhone(), aesKey);
                installmentDebtPageVo.setPhone(decryptPhone);
            }
            write.write(list, writeSheet);
            write.finish();
            fileOutputStream.flush();
            //修改文件状态 导出成功
            missionCenterInfo.setFileStatus(SysConstant.YSZT_FILE_STATUS_TOW);
            missionCenterInfo.setFileUrl(exportFile + "/" + companyId + "/" + name + ".xlsx");
            missionCenterInfoMapper.updateById(missionCenterInfo);
        } catch (Exception e) {
            //修改文件状态 导出失败
            missionCenterInfo.setFileStatus(SysConstant.YSZT_FILE_STATUS_THREE);
            missionCenterInfoMapper.updateById(missionCenterInfo);
            e.printStackTrace();
        } finally {
            try {
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
